#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include "affichage.h"


/* Quelques fonctions d'affichage standard */
static void setPixel(const int x, const int y, Uint32 couleur, SDL_Surface* ecran)
{
	SDL_Surface *pixel;
	SDL_Rect position;

	position.x = x;
	position.y = y;
    pixel = SDL_CreateRGBSurface(SDL_HWSURFACE, 1, 1, 32, 0, 0, 0, 0);

	SDL_FillRect(pixel, NULL, couleur);
	SDL_BlitSurface(pixel, NULL, ecran, &position);
    SDL_FreeSurface(pixel);
}


static int estDansEcran(const int x, const int y)
{
	if (x<0)
	{ return 0; }
	if (y<0)
	{ return 0; }
	if (x>LARGEUR)
	{ return 0; }
	if (y>HAUTEUR-1)
	{ return 0; }

	return 1;
}


static void setGrosPixel(const int x, const int y, const int rayon, Uint32 couleur, SDL_Surface* ecran)
{
	int i, j;
	for (i=x-rayon;i<=x+rayon;i++)
	{
		for (j=y-rayon;j<=y+rayon;j++)
		{
			if (estDansEcran(i,j))
			{
				setPixel(i,j,couleur,ecran);
			}	
		}
	}
}


static void affichageRond(const int x, const int y, const int rayon, const Uint32 couleur, SDL_Surface* ecran)
{
	int i, j;

	for (i=-rayon;i<=rayon;i++)
	{
		for (j=-rayon;j<=rayon;j++)
		{
			if (((i*i)+(j*j) <= rayon*rayon) && (estDansEcran(x+i,y+j)))
			{
				setPixel(x+i,y+j,couleur,ecran);
			}
		}
	}
}


static void affichageTrait(const int x0, const int y0, const int x1, const int y1,
						   const int epaisseur, const Uint32 couleur, SDL_Surface* ecran)
{
	int i, longueur, x, y;

	longueur = fabs(x1-x0) + fabs(y1-y0);
	for(i=0;i<longueur;i++)
	{
		x = (int) ((float)x0 + ((float)i/(float)longueur)*((float)x1-(float)x0));
		y = (int) ((float)y0 + ((float)i/(float)longueur)*((float)y1-(float)y0));
		setGrosPixel(x, y, epaisseur, couleur, ecran);
	}
}



void pause()
{
	SDL_Event evenement;
	do SDL_WaitEvent(&evenement);
	while(evenement.type != SDL_QUIT && evenement.type != SDL_KEYDOWN);
}



void setCoordonneesEuclidiennes(Graphe* g)
{
	int i;
	int x, y;
	int maxX, maxY, minX, minY;
	Noeud n;

	n = getINoeud(g,0);
	maxX = getPosXNoeud(&n);
	maxY = getPosYNoeud(&n);
	minX = getPosXNoeud(&n);
	minY = getPosYNoeud(&n);

	for(i=1;i<getNbNGraphe(g);i++)
	{
		n = getINoeud(g,i);
		if (maxX < getPosXNoeud(&n))
		{ maxX = getPosXNoeud(&n); }
		if (maxY < getPosYNoeud(&n))
		{ maxY = getPosYNoeud(&n); }
		if (minX > getPosXNoeud(&n))
		{ minX = getPosXNoeud(&n); }
		if (minY > getPosYNoeud(&n))
		{ minY = getPosYNoeud(&n); }
	}

	for(i=0;i<getNbNGraphe(g);i++)
	{
		n = getINoeud(g,i);

		x = getPosXNoeud(&n) - minX;
		x = MARGE + (int)(((float)((LARGEUR-2*MARGE)*x))/(float)(maxX-minX));
		y = getPosYNoeud(&n) - minY;
		y = MARGE + (int)(((float)((HAUTEUR-2*MARGE)*y))/(float)(maxY-minY));

		setCoordonneesINoeudGraphe(g,i,x,y);
	}
}


void setCoordonneesLattice(Graphe* g)
{
	int i, j;
	int x, y;
	int racine;

	racine = (int)(sqrt(getNbNGraphe(g))) + 1;


	y = 0;
	for (i=0;i<racine;i++)
	{
		x = 0;

		for(j=0;j<racine;j++)
		{
			if ((i*racine+j) < getNbNGraphe(g))
			{
				setCoordonneesINoeudGraphe(g,i*racine+j,x,y);
			}
			x++;
		}

		y++;
	}

	setCoordonneesEuclidiennes(g);
}


void setCoordonneesCercle(Graphe* g)
{
	int i;
	int n;
	int x, y;
	float rho, theta;

	n = getNbNGraphe(g);
	rho = 100*n;
	
	for (i=0;i<getNbNGraphe(g);i++)
	{
		theta = (2.*i*3.14152)/((float)n);

		x = (cos(theta) * rho) + 2*rho;
		y = (sin(theta) * rho) + 2*rho;

		setCoordonneesINoeudGraphe(g,i,x,y);
	}

	setCoordonneesEuclidiennes(g);
}



void affichageGraphe(Graphe* g, const int villes, const int routes, const Arete* solution, const int longsol, SDL_Surface* ecran)
{
	affichageVilles(g,villes,ecran);
	affichageRoutes(g,routes,ecran);
	affichageVilles(g,0,ecran);


	SDL_Flip(ecran);
	pause();

	affichageRoutesImportantes(g,solution,longsol,routes,ecran);
	affichageVilles(g,0,ecran);

	SDL_Flip(ecran);
}


void affichageRoutesImportantes(const Graphe* g, const Arete* tab, const int longueur, const int routes, SDL_Surface* ecran)
{
	int i, j;
	int x0, y0, x1, y1;
	int poids, poidsmax, poidsmin;
	Uint32 couleur;
	Arete a;
	Noeud *n0, *n1;

	couleur = ROSE;

	if (routes == 1)
	{
		a = getAreteNoeuds(g,0,1);
		poidsmax = getPoidsArete(&a);
		poidsmin = getPoidsArete(&a);

		for(i=1;i<(getNbNGraphe(g));i++)
		{
			for(j=i+1;j<(getNbNGraphe(g));j++)
			{
				a = getAreteNoeuds(g,i,j);
				if (poidsmax < getPoidsArete(&a))
				{ poidsmax = getPoidsArete(&a); }
				if (poidsmin > getPoidsArete(&a))
				{ poidsmin = getPoidsArete(&a); }
			}
		}

		for(i=0;i<longueur;i++)
		{
			a = tab[i];
			n0 = getCheminIArete(&a,0);
			n1 = getCheminIArete(&a,1);

			x0 = getPosXNoeud(n0);
			y0 = getPosYNoeud(n0);
			x1 = getPosXNoeud(n1);
			y1 = getPosYNoeud(n1);

			poids = getPoidsArete(&a) - poidsmin;
			poids = (int) (((float)(8*poids))/((float)(poidsmax-poidsmin)));

			affichageTrait(x0, y0, x1, y1, poids, couleur, ecran);
		}
	}


	else
	{	
		for(i=0;i<longueur;i++)
		{
				a = tab[i];
				n0 = getCheminIArete(&a,0);
				n1 = getCheminIArete(&a,1);

				x0 = getPosXNoeud(n0);
				y0 = getPosYNoeud(n0);
				x1 = getPosXNoeud(n1);
				y1 = getPosYNoeud(n1);

				affichageTrait(x0, y0, x1, y1, 3, couleur, ecran);
		}
	}
}



void affichageRoutes(const Graphe* g, const int routes, SDL_Surface* ecran)
{
	int i, j;
	int x0, y0, x1, y1;
	int poids, poidsmax, poidsmin;
	Uint32 couleur;
	Arete a;
	Noeud *n0, *n1;

	couleur = BLEUCLAIR;

	if (routes == 1)
	{
		a = getAreteNoeuds(g,0,1);
		poidsmax = getPoidsArete(&a);
		poidsmin = getPoidsArete(&a);

		for(i=1;i<(getNbNGraphe(g));i++)
		{
			for(j=i+1;j<(getNbNGraphe(g));j++)
			{
				a = getAreteNoeuds(g,i,j);
				if (poidsmax < getPoidsArete(&a))
				{ poidsmax = getPoidsArete(&a); }
				if (poidsmin > getPoidsArete(&a))
				{ poidsmin = getPoidsArete(&a); }
			}
		}

		for(i=0;i<(getNbNGraphe(g));i++)
		{
			for(j=i+1;j<(getNbNGraphe(g));j++)
			{
				a = getAreteNoeuds(g,i,j);
				if (getLongueurArete(&a) == 2)
				{
					n0 = getCheminIArete(&a,0);
					n1 = getCheminIArete(&a,1);

					x0 = getPosXNoeud(n0);
					y0 = getPosYNoeud(n0);
					x1 = getPosXNoeud(n1);
					y1 = getPosYNoeud(n1);

					poids = getPoidsArete(&a) - poidsmin;
					poids = (int) (((float)(8*poids))/((float)(poidsmax-poidsmin)));

					affichageTrait(x0, y0, x1, y1, poids, couleur, ecran);
				}
			}
		}
	}


	else
	{	
		for(i=0;i<(getNbNGraphe(g));i++)
		{
			for(j=i+1;j<(getNbNGraphe(g));j++)
			{
				a = getAreteNoeuds(g,i,j);
				if (getLongueurArete(&a) == 2)
				{
					n0 = getCheminIArete(&a,0);
					n1 = getCheminIArete(&a,1);

					x0 = getPosXNoeud(n0);
					y0 = getPosYNoeud(n0);
					x1 = getPosXNoeud(n1);
					y1 = getPosYNoeud(n1);

					affichageTrait(x0, y0, x1, y1, 3, couleur, ecran);
				}
			}
		}
	}
}


void affichageVilles(Graphe* g, const int villes, SDL_Surface* ecran)
{
	int i, j, x, y;
	Uint32 couleur;
	Noeud n;

	if (villes == 1)
	{ setCoordonneesEuclidiennes(g); }
	if (villes == 2)
	{ setCoordonneesLattice(g); }
	else if (villes == 3)
	{ setCoordonneesCercle(g); }

	couleur = BLEU;

	for (i=0;i<(getNbNGraphe(g));i++)
	{
		n = getINoeud(g,i);
		x = getPosXNoeud(&n);
		y = getPosYNoeud(&n);
		assert(x>=MARGE);
		assert(x<=LARGEUR-MARGE);
		assert(y>=MARGE);
		assert(y<=HAUTEUR-MARGE);

		affichageRond(x,y,10,couleur,ecran);
	}

	couleur = ROUGE;

	for (i=0;i<(getNbIGraphe(g));i++)
	{
		j = getIndiceImportant(g,i);
		n = getINoeud(g,j);
		x = getPosXNoeud(&n);
		y = getPosYNoeud(&n);

		affichageRond(x,y,10,couleur,ecran);
	}
}








int testAffichage(SDL_Surface *ecran)
{
	Uint32 couleur;
	int i, j, x, y;
	Graphe g;
	Arete* tab;
	Arete a;

	srand(time(NULL));


	printf("\nTEST DU MODULE AFFICHAGE\n");

	printf("\nAffichage de 100 pixels bleus\n");
	couleur = BLEU;
	for(i=0;i<100;i++)
	{
		setPixel(rand()%LARGEUR,rand()%HAUTEUR,couleur,ecran);
	}
	SDL_Flip(ecran);

	printf("Appuyer sur une touche pour continuer\n");
	pause();

	printf("\nAffichage de 100 gros pixels rouges\n");
	couleur = ROUGE;
	for(i=0;i<100;i++)
	{
		setGrosPixel(rand()%LARGEUR,rand()%HAUTEUR,rand()%9+2,couleur,ecran);
	}
	SDL_Flip(ecran);

	printf("Appuyer sur une touche pour continuer\n");
	pause();

	printf("\nAffichage de 100 ronds cyans\n");
	couleur = BLEUCLAIR;
	for(i=0;i<100;i++)
	{
		affichageRond(rand()%LARGEUR,rand()%HAUTEUR,rand()%19+2,couleur,ecran);
	}
	SDL_Flip(ecran);

	printf("Appuyer sur une touche pour continuer\n");
	pause();

	printf("\nAffichage de 3 faisceaux de 5 traits roses\n");
	couleur = ROSE;
	for(i=0;i<3;i++)
	{
		x = rand()%LARGEUR;
		y = rand()%HAUTEUR;
		for(j=0;j<5;j++)
		{
			affichageTrait(x,y,rand()%LARGEUR,rand()%HAUTEUR,rand()%4+2,couleur,ecran);
		}
	}
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();


	g = nouveauGrapheFichier2("test/test2.txt");

    SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0xFF, 0xFF, 0xFF));
	SDL_Flip(ecran);
	printf("\nPremier affichage des villes : naturel\n");
	affichageVilles(&g, 1, ecran);
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();

    SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0xFF, 0xFF, 0xFF));
	SDL_Flip(ecran);
	printf("\nDeuxieme affichage des villes : lattice\n");
	affichageVilles(&g, 2, ecran);
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();

    SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0xFF, 0xFF, 0xFF));
	SDL_Flip(ecran);
	printf("\nTroisieme affichage des villes : circulaire\n");
	affichageVilles(&g, 3, ecran);
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();

    SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0xFF, 0xFF, 0xFF));
	SDL_Flip(ecran);
	printf("\nPremier affichage des routes : epaisseur fixe\n");
	affichageVilles(&g, 0, ecran);
	affichageRoutes(&g, 0, ecran);
	affichageVilles(&g, 0, ecran);
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();

    SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0xFF, 0xFF, 0xFF));
	SDL_Flip(ecran);
	printf("\nDeuxieme affichage des routes : epaisseur variable\n");
	affichageVilles(&g, 0, ecran);
	affichageRoutes(&g, 1, ecran);
	affichageVilles(&g, 0, ecran);
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();

	tab = (Arete*) malloc(getNbPGraphe(&g)*sizeof(Arete));
	x = 0;
	for(i=0;i<getNbNGraphe(&g);i++)
	{
		for(j=i+1;j<getNbNGraphe(&g);j++)
		{
			a = getAreteNoeuds(&g,i,j);
			if(getLongueurArete(&a) != 0)
			{
				tab[x] = a;
				x++;
			}
		}
	}
    SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0xFF, 0xFF, 0xFF));
	SDL_Flip(ecran);
	printf("\nPremier affichage des routes \"importantes\" : epaisseur fixe\n");
	affichageVilles(&g, 0, ecran);
	affichageRoutes(&g, 0, ecran);
	affichageRoutesImportantes(&g, tab, x, 0, ecran);
	affichageVilles(&g, 0, ecran);
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();


    SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 0xFF, 0xFF, 0xFF));
	SDL_Flip(ecran);
	printf("\nDeuxieme affichage des routes \"importantes\" : epaisseur variable\n");
	affichageVilles(&g, 0, ecran);
	affichageRoutes(&g, 1, ecran);
	affichageRoutesImportantes(&g, tab, x, 1, ecran);
	affichageVilles(&g, 0, ecran);
	SDL_Flip(ecran);
	printf("Appuyer sur une touche pour continuer\n");
	pause();

	free(tab);
	testamentGraphe(&g);

	printf("\nLe test est un succès.\n");
	return 0;
}

